﻿using FR.CodeVisualizer.Visualizers;
using Microsoft.VisualStudio.DebuggerVisualizers;
using System;
using System.Data.Entity;
using System.Data.Entity.Infrastructure;
using System.Data.EntityClient;
using System.Data.Objects;
using System.Linq;
using System.Reflection;
using System.Runtime.Serialization.Formatters.Binary;
using System.Text;

namespace FR.CodeVisualizer.ObjectSource
{
    public class EFDbContextVisualizerObjectSource : VisualizerObjectSource
    {
        public override void GetData(object target, System.IO.Stream outgoingData)
        {
            SQLQueryOptions sqlOptions = null;

            try
            {
                if (target is IQueryable)
                {
                    sqlOptions = (target as IQueryable).ToSqlString();
                }
                else if (target is DbContext)
                {
                    sqlOptions = (target as DbContext).ToSqlString();
                }
            }
            catch (Exception ex)
            {
                sqlOptions = new SQLQueryOptions();
                sqlOptions.SetExceptionMessage(ex);
            }

            StreamSerializer.ObjectToStream(outgoingData, sqlOptions);
        }
    }

    public static class DbContextExtensionMethods
    {
        public static SQLQueryOptions ToSqlString(this IQueryable queryable)
        {
            SQLQueryOptions sqlOptions = new SQLQueryOptions();
            sqlOptions.IsQuery = true;

            var iqProp = queryable.GetType().GetProperty("InternalQuery", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);

            var iq = iqProp.GetValue(queryable);

            var oqProp = iq.GetType().GetProperty("ObjectQuery", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);

            var oq = oqProp.GetValue(iq);

            var objectQuery = oq as ObjectQuery;

            return objectQuery.ToSqlString();
        }

        public static SQLQueryOptions ToSqlString(this DbContext dbContext)
        {
            SQLQueryOptions sqlOptions = new SQLQueryOptions();

            var objectContext = ((IObjectContextAdapter)dbContext).ObjectContext;

            sqlOptions.ConnectionString = (objectContext.Connection as EntityConnection).StoreConnection.ConnectionString;
            sqlOptions.SQLCommand = ContextHelper.GetSQLCommands(objectContext);

            return sqlOptions;
        }
    }
}
